﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Aquasoft.Iszr.Proxy.Properties;

namespace Aquasoft.Iszr.Proxy.WebServices
{
    public interface IIszrServiceManagerCallEvents
    {
        event Action<IszrServiceBase> ServiceCreated;
        event Action<IszrServiceBase, object> BeforeCallService;
        event Action<IszrServiceBase, object, Exception> ErrorCallService;
        event Action<IszrServiceBase, object, object> AfterCallService;

    }
    public class DefaultIszrServiceManager : IIszrServiceManager, IIszrServiceManagerCallEvents
    {
        public static DefaultIszrServiceManager Instance { get { return (DefaultIszrServiceManager)IszrServiceManager.Instance; } }

        public class IszrServiceConfig
        {
            public string ServiceCode { get; private set; }
            public bool CanCallSync { get; private set; }
            public bool CanCallAsync { get; private set; }

            internal IszrServiceConfig(string code, bool canCallSync, bool canCallAsync)
            {
                this.ServiceCode = code;
                this.CanCallSync = canCallSync;
                this.CanCallAsync = canCallAsync;
            }
        }

        #region Service configs

        private readonly Dictionary<Type, IszrServiceConfig> __serviceCodeStorage =
            new Dictionary<Type, IszrServiceConfig>()
            {
                // ROB
                { typeof(IszrRobCtiAifoBinding), new IszrServiceConfig("E03", true, true) },
                { typeof(IszrRobAutentizaceBinding), new IszrServiceConfig("E04", true, true) },
                { typeof(IszrRobCtiPodleUdajuBinding), new IszrServiceConfig("E05", true, true) },

                // * ROB ostatni
                { typeof(IszrRobCtiZmenyBinding), new IszrServiceConfig("E07", false, true) },
                { typeof(IszrRobCtiHromadneAifoBinding), new IszrServiceConfig("E08", false, true) },

                // ROS
                { typeof(IszrRosPridelIcoBinding), new IszrServiceConfig("E16", true, true) },
                { typeof(IszrRosVlozOsobuBinding), new IszrServiceConfig("E18", false, true) },
                { typeof(IszrRosZmenOsobuBinding), new IszrServiceConfig("E19", false, true) },
                { typeof(IszrRosCtiIcoBinding), new IszrServiceConfig("E20", true, true) },
                { typeof(IszrRosCtiAifoBinding), new IszrServiceConfig("E21", true, true) },
                { typeof(IszrRosCtiPodleUdajuBinding), new IszrServiceConfig("E22", true, true) },
                { typeof(IszrRosVymazOsobuBinding), new IszrServiceConfig("E24", false, true) },

                // * ROS ostatni
                { typeof(IszrRosCtiZmenyBinding), new IszrServiceConfig("E28", false, true) },
                { typeof(IszrRosCtiSeznamIcoBinding), new IszrServiceConfig("E29", false, true) },

                // RUIAN
                { typeof(IszrRuianVyhledejPrvekMopBinding), new IszrServiceConfig("E34g", true, true) },
                { typeof(IszrRuianCtiAdresuBinding), new IszrServiceConfig("E36", true, true) },
                { typeof(IszrRuianVyhledejAdresuBinding), new IszrServiceConfig("E37", true, true) },
                { typeof(IszrRuianCtiSeznamZmenBinding), new IszrServiceConfig("E38", false, true) },

                // * RUIAN Soubor dat
                { typeof(IszrRuianSouboryDatBinding), new IszrServiceConfig("E40", true, false) },

                // ORG
                { typeof(IszrOrgPrihlasAifoBinding), new IszrServiceConfig("E45", true, false) },
                { typeof(IszrOrgOdhlasAifoBinding), new IszrServiceConfig("E46", false, true) },

                // REKLAMACE
                { typeof(IszrReklamujUdajeRobBinding), new IszrServiceConfig("E62", false, true) },
                { typeof(IszrReklamujUdajeRosBinding), new IszrServiceConfig("E63", false, true) },

                // Fronty
                { typeof(IszrAsyncVypisFrontyBinding), new IszrServiceConfig("E99", true, false) },
                { typeof(IszrAsyncOdpovedZFrontyBinding), new IszrServiceConfig("E100", true, false) },
                { typeof(IszrAsyncSmazatFrontuBinding), new IszrServiceConfig("E101", true, false) },

                // Ciselniky
                { typeof(IszrCtiSeznamCiselnikuBinding), new IszrServiceConfig("E97", true, false) },

                // RPP
                { typeof(IszrRppVlozRozhodnutiBinding), new IszrServiceConfig("E115", false, true)},
                { typeof(IszrRppVymazRozhodnutiBinding), new IszrServiceConfig("E118", false, true)},
                { typeof(IszrRppVypisPusobnostOvmBinding), new IszrServiceConfig("E130", true, true)},
            };

        #endregion

        public IEnumerable<Type> GetAllServices()
        {
            return __serviceCodeStorage.Keys;
        }

        public IszrServiceConfig GetServiceInfo(Type serviceType)
        {
            return __serviceCodeStorage[serviceType];
        }

        public string GetServiceUri(Type serviceType, bool? callSync = null)
        {
            var info = GetServiceInfo(serviceType);
            return string.Format("{0}/{1}?{2}", Settings.Default.BaseUri, info.ServiceCode, (callSync ?? info.CanCallSync) ? "sync" : "async");
        }

        public string GetServiceCode(Type serviceType)
        {
            return GetServiceInfo(serviceType).ServiceCode;
        }

        // public events
        public event Action<IszrServiceBase> ServiceCreated;
        public event Action<IszrServiceBase, object> BeforeCallService;
        public event Action<IszrServiceBase, object, Exception> ErrorCallService;
        public event Action<IszrServiceBase, object, object> AfterCallService;

        #region IIszrServiceManager implementation
        
        void IIszrServiceManager.OnBeforeCallService<TI, TO>(IszrService<TI, TO> iszrService, object input)
        {
            if (BeforeCallService != null)
            {
                BeforeCallService(iszrService, input);
            }
        }

        void IIszrServiceManager.OnErrorCallService<TI, TO>(IszrService<TI, TO> iszrService, object input, Exception error)
        {
            if (ErrorCallService != null)
            {
                ErrorCallService(iszrService, input, error);
            }
        }

        void IIszrServiceManager.OnAfterCallService<TI, TO>(IszrService<TI, TO> iszrService, object input, object result)
        {
            if (AfterCallService != null)
            {
                AfterCallService(iszrService, input, result);
            }
        }

        void IIszrServiceManager.OnServiceCreated<TI, TO>(IszrService<TI, TO> service)
        {
            // url
            service.Url = GetServiceUri(service.GetType());
            // certificate
            if (!String.IsNullOrEmpty(Settings.Default.CertificateSN))
            {
                var cert = CertUtils.FindCert(Settings.Default.CertificateSN);
                if (cert != null)
                {
                    service.ClientCertificates.Add(cert);
                }
            }
            if (ServiceCreated != null)
            {
                ServiceCreated(service);
            }
        }

        #endregion
    }
}
